package com.vhall.component.service.room.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.room.entity.RoomsEntity;
import com.vhall.component.entity.room.enums.LiveRoomTypeEnum;
import com.vhall.component.entity.room.enums.RoomAuditStatusEnum;
import com.vhall.component.entity.room.enums.RoomAuditWhichEnum;
import com.vhall.component.entity.room.vo.*;
import com.vhall.component.entity.subject.enums.StatusEnum;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.constant.ConstStr;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomConstant;
import com.vhall.component.plugin.common.enums.DeleteStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.service.room.RoomAdminService;
import com.vhall.component.service.room.utils.RoomUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Preconditions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author guoxin.wang
 * @date 2021-07-30 17:00
 */
@Slf4j
@Service
public class RoomAdminServiceImpl extends RoomBaseService implements RoomAdminService {

    @Override
    public RoomAdminListRspVO list(RoomAdminListReqVO reqVO) {
        RoomAdminListRspVO result = new RoomAdminListRspVO();
        // 时间赋值
        assemblyTime(reqVO);
        Page<RoomsEntity> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());
        reqVO.setAuditStatus(Collections.singletonList(RoomAuditStatusEnum.APPROVED.getAuditStatus()));
        IPage<RoomAdminListRspSingleVO> pages;
        if (CollectionUtils.isNotEmpty(reqVO.getLiveTypes())
                && reqVO.getLiveTypes().size() == 1
                && reqVO.getLiveTypes().get(0).equals(LiveRoomTypeEnum.ON_DEMAND.getType())) {
            pages = roomMapper.selectAdminListFoDemand(page, reqVO);
        } else {
            pages = roomMapper.selectAdminList(page, reqVO);
        }

        List<RoomAdminListRspSingleVO> data = new ArrayList<>();
        assemblyData(pages, data);
        result.setCurrentPage(reqVO.getPage());
        result.setTotal(pages == null ? 0 : (int) pages.getTotal());
        result.setPerPage(reqVO.getPageSize());
        result.setData(data);
        return result;
    }

    /**
     * 审核列表
     */
    @Override
    public RoomAdminListRspVO examineListLive(RoomAdminListReqVO reqVO) {
        RoomAdminListRspVO result = new RoomAdminListRspVO();
        // 时间赋值
        assemblyTime(reqVO);

        Page<RoomsEntity> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());

        List<Integer> auditLists = Lists.newArrayList();
        if (reqVO.getAuditStatus() == null || reqVO.getAuditStatus().isEmpty()) {
            auditLists.add(RoomAuditStatusEnum.APPROVED.getAuditStatus());
            auditLists.add(RoomAuditStatusEnum.REJECTION.getAuditStatus());
            auditLists.add(RoomAuditStatusEnum.CHECK_PENDING.getAuditStatus());
        } else {
            auditLists.addAll(reqVO.getAuditStatus());
        }
        reqVO.setAuditStatus(auditLists);

        IPage<RoomAdminListRspSingleVO> pages;
        if (CollectionUtils.isNotEmpty(reqVO.getLiveTypes())
                && reqVO.getLiveTypes().size() == 1
                && reqVO.getLiveTypes().contains(LiveRoomTypeEnum.ON_DEMAND.getType())) {
            pages = roomMapper.selectExamineListVideo(page, reqVO);
        } else {
            pages = roomMapper.selectExamineList(page, reqVO);
        }

        List<RoomAdminListRspSingleVO> data = new ArrayList<>();
        assemblyData(pages, data);
        result.setCurrentPage(reqVO.getPage());
        result.setTotal(pages == null ? 0 : (int) pages.getTotal());
        result.setPerPage(reqVO.getPageSize());
        result.setData(data);
        return result;
    }

    private void assemblyLiveTime(RoomAdminListRspSingleVO single) {
        RoomsEntity roomsEntity = new RoomsEntity();
        BeanCopyUtil.copy(single, roomsEntity);
        single.setLiveTime(findLiveTime(roomsEntity));
    }


    private void assemblyData(IPage<RoomAdminListRspSingleVO> pages, List<RoomAdminListRspSingleVO> data) {
        if (pages != null && pages.getRecords() != null && CollectionUtils.isNotEmpty(pages.getRecords())) {
            List<RoomAdminListRspSingleVO> records = pages.getRecords();
            Map<Integer, String> liveRoomTypeMap = new HashMap<>(4);
            liveRoomTypeMap.put(0, "无");
            liveRoomTypeMap.put(1, "R1");
            liveRoomTypeMap.put(2, "R3");
            Map<Integer, String> statusMap = new HashMap<>(4);
            statusMap.put(0, "待直播");
            statusMap.put(1, "直播中");
            statusMap.put(2, "已结束");
            for (RoomAdminListRspSingleVO single : records) {
                // rooms表中没有的字段的处理。
                single.setDesc(single.getIntroduction());
                single.setImage(single.getCoverImage());
                single.setLiveRoomTypeStr(liveRoomTypeMap.getOrDefault(single.getLiveType(), ""));
                single.setName(single.getSubject());
                single.setBeginTime(single.getStartTime());
                String statusStr = RoomUtils.getRoomStatusStr(single.getAuditStatus(), single.getStatus(), roomAuditWitch);
                single.setStatusStr(statusStr);
                single.setViewUrl(webDomain + "/live-room/watch/" + single.getIlId());
                single.setWatchUrl(webDomain + "/live-room/watch/" + single.getIlId());

                //查询 直播时长
                assemblyLiveTime(single);
                single.setAuditStatusName(RoomAuditStatusEnum.getDescription(single.getAuditStatus()));
                data.add(single);
            }
        }
    }

    /**
     * 时间赋值
     */
    private void assemblyTime(RoomAdminListReqVO reqVO) {
        if (StringUtils.isNotBlank(reqVO.getEndTime())) {
            String endTime = reqVO.getEndTime();
            if (endTime.contains(ConstStr.TIME_ZERO)) {
                endTime = endTime.replace(ConstStr.TIME_ZERO, ConstStr.TIME_FULL);
            } else {
                boolean contains = endTime.contains(" ");
                if (contains) {
                    String[] s = endTime.split(" ");
                    endTime = s[0] + " " + ConstStr.TIME_FULL;
                } else {
                    endTime = endTime + " " + ConstStr.TIME_FULL;
                }
            }
            reqVO.setEndTime(endTime);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> delete(RoomAdminDelVO reqVO) {
        List<String> result = new ArrayList<>();
        List<String> roomIds = Splitter.on(",").splitToList(reqVO.getRoomIds());
        LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomsEntity::getStatus, RoomConstant.STATUS_START);
        wrapper.in(RoomsEntity::getRoomId, roomIds);
        Integer count = roomMapper.selectCount(wrapper);
        if (count > 0) {
            throw new BusinessException(BizErrorCode.BIZ_LIVING_NOT_DELETE);
        }
        wrapper.clear();
        wrapper.ne(RoomsEntity::getStatus, RoomConstant.STATUS_START);
        wrapper.in(RoomsEntity::getRoomId, roomIds);
        List<RoomsEntity> roomEntities = roomMapper.selectList(wrapper);
        for (RoomsEntity roomEntity : roomEntities) {
            wrapper.clear();
            wrapper.eq(RoomsEntity::getIlId, roomEntity.getIlId());
            wrapper.ne(RoomsEntity::getStatus, RoomConstant.STATUS_START);
            int delCount = roomMapper.delete(wrapper);
            if (delCount > 0) {
                redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomEntity.getRoomId());
                redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomEntity.getIlId());
                delPassRoom(roomEntity);
                redisTemplate.delete(RedisKey.WARM_INFO + roomEntity.getIlId());
                result.add(roomEntity.getRoomId());
            }
        }
        return result;
    }

    @Override
    public Boolean auditRoom(RoomAuditVO vo) {

        Preconditions.checkArgument(StringUtils.isNotBlank(vo.getRoomId()), "房间号不能为空！");

        // 直播中禁止编辑
        RoomsEntity room = prohibitEditing(vo.getRoomId());

        basicValidateVo(vo);

        Token token = TokenThreadLocal.getToken();

        if (RoomAuditWhichEnum.CLOSE_ROOM_AUDIT.getStatus().equals(roomAuditWitch)) {
            throw new BusinessException(BizErrorCode.COMP_ROOM_AUDIT_CLOSE_ERR);
        }


        Preconditions.checkArgument(room.getAuditStatus().equals(RoomAuditStatusEnum.CHECK_PENDING.getAuditStatus()), "只有送审之后才能审核！");

        room.setSubject(vo.getName());

        if (StringUtils.isNotBlank(vo.getBeginTime())) {
            room.setStartTime(LocalDateTimeUtil.parse(vo.getBeginTime(), DatePattern.NORM_DATETIME_PATTERN));
        }

        room.setVideoType(vo.getVideoType());
        if (StringUtils.isNotBlank(vo.getImageUrl())) {
            room.setCoverImage(vo.getImageUrl());
        }

        switch (Objects.requireNonNull(LiveRoomTypeEnum.parse(room.getLiveType()))) {
            case LIVE_BROADCAST:
                break;
            case FAKE_LIVE_BROADCAST:
                room.setDemandVodId(vo.getDemandVodId());
                break;
            case ON_DEMAND:
                room.setRecordId(vo.getDemandVodId());
                break;
            default:
                break;
        }

        room.setAuditStatus(vo.getAuditStatus());
        room.setAuditNote(vo.getAuditNote());
        room.setIntroduction(StringUtils.isBlank(vo.getIntroduction()) ? "" : vo.getIntroduction());
        room.setShareIntroduction(StringUtils.isBlank(vo.getShareIntroduction()) ? "" : vo.getShareIntroduction());
        room.setUpdatedAt(LocalDateTime.now());
        room.setReviewer(token.getAccountId());
        room.setPosterUrl(StringUtils.isBlank(vo.getPosterUrl()) ? "" : vo.getPosterUrl());

        Preconditions.checkArgument(roomMapper.updateById(room) > 0, "更新失败！");

        Object cachedObj = redisTemplate.opsForValue().get(RedisKey.ROOM_INFO_BY_ROOM_ID + vo.getRoomId());
        if (Objects.nonNull(cachedObj)) {
            RoomsEntityDTO roomsEntityDTO = JSON.parseObject(cachedObj.toString(), RoomsEntityDTO.class);
            redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomsEntityDTO.getRoomId());
            redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomsEntityDTO.getIlId());
        }

        // 录播视频加入缓存，给定时调度使用
        addRecordedVideoToCache(room, vo.getAuditStatus());

        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setAsHotspot(RoomOperationStatusVO vo) {

        RoomsEntity roomsEntity = getRoomsEntity(vo);

        Preconditions.checkArgument(StringUtils.isNotBlank(roomsEntity.getPosterUrl()), "请先上传竖版海报");

        roomInnerService.updateByIl(RoomsEntityDTO.builder()
                .ilId(roomsEntity.getIlId()).roomId(roomsEntity.getRoomId())
                .hotStatus(vo.getStatus()).build());

        LambdaQueryWrapper<RoomsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomsEntity::getHotStatus, StatusEnum.OPEN.getValue());
        where.eq(RoomsEntity::getIsDelete, DeleteStatusEnum.NO_DELETE.getStatus());
        List<RoomsEntity> roomsEntities = roomMapper.selectList(where);

        Preconditions.checkArgument(CollectionUtils.isEmpty(roomsEntities) || roomsEntities.size() <= 6, "最多支持热点6个");

        return true;
    }


    private RoomsEntity getRoomsEntity(RoomOperationStatusVO vo) {
        Preconditions.checkArgument(StringUtils.isNotBlank(vo.getRoomId()), "房间号不能为空！");
        LambdaQueryWrapper<RoomsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomsEntity::getRoomId, vo.getRoomId());
        RoomsEntity roomsEntity = roomMapper.selectOne(where);
        Preconditions.checkArgument(roomsEntity != null, "房间号传入有误！");
        return roomsEntity;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean recommendedHomePage(RoomOperationStatusVO vo) {

        RoomsEntity roomsEntity = getRoomsEntity(vo);


        roomInnerService.updateByIl(RoomsEntityDTO.builder()
                .ilId(roomsEntity.getIlId()).roomId(roomsEntity.getRoomId())
                .recommendedStatus(vo.getStatus()).build());


        LambdaQueryWrapper<RoomsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomsEntity::getRecommendedStatus, StatusEnum.OPEN.getValue());
        where.eq(RoomsEntity::getIsDelete, DeleteStatusEnum.NO_DELETE.getStatus());
        List<RoomsEntity> roomsEntities = roomMapper.selectList(where);

        Preconditions.checkArgument(CollectionUtils.isEmpty(roomsEntities) || roomsEntities.size() <= 3, "最多支持推荐3个");

        return true;
    }

    @Override
    public Boolean loadOrUnload(RoomOperationStatusVO vo) {

        RoomsEntity roomsEntity = getRoomsEntity(vo);

        RoomsEntityDTO roomsEntityDTO = new RoomsEntityDTO();
        roomsEntityDTO.setIlId(roomsEntity.getIlId());
        roomsEntityDTO.setRoomId(roomsEntity.getRoomId());
        roomsEntityDTO.setLoadOrUnload(vo.getStatus());
        if (vo.getStatus().equals(StatusEnum.OPEN.getValue())) {
            roomsEntityDTO.setLoadOrUnloadAt(LocalDateTimeUtil.now());
        }

        if (roomsEntity.getLiveType().equals(LiveRoomTypeEnum.ON_DEMAND.getType())
                && vo.getStatus().equals(StatusEnum.OPEN.getValue())) {
            roomsEntityDTO.setStartTime(LocalDateTime.now());
        }

        roomInnerService.updateByIl(roomsEntityDTO);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean topRoom(RoomOperationStatusVO vo) {

        RoomsEntity roomsEntity = getRoomsEntity(vo);
        if (vo.getStatus().equals(StatusEnum.OPEN.getValue())) {
            roomInnerService.updateByIl(RoomsEntityDTO.builder()
                    .ilId(roomsEntity.getIlId())
                    .roomId(roomsEntity.getRoomId())
                    .topStatusAt(LocalDateTime.now())
                    .topStatus(StatusEnum.OPEN.getValue()).build());
        } else {
            // 删除置顶时间
            LambdaUpdateWrapper<RoomsEntity> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(RoomsEntity::getIlId, roomsEntity.getIlId());
            wrapper.set(RoomsEntity::getTopStatusAt, null);
            wrapper.set(RoomsEntity::getTopStatus, StatusEnum.CLOSE.getValue());
            roomMapper.update(null, wrapper);

            // 删除房间缓存
            redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomsEntity.getRoomId());
            redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + roomsEntity.getIlId());
        }


        return true;
    }

    /**
     * 删除pass房间
     *
     * @param room 房间对象
     */
    private void delPassRoom(RoomsEntity room) {
        paasService.delRoom(room.getRoomId());
        paasService.delInav(room.getInavId());
        paasService.delChannel(room.getChannelId());
    }


}
